package wxdb.record;

import static java.sql.Types.INTEGER;

import java.io.Serializable;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;

import wxdb.tx.Transaction;

public class TableInfo implements Serializable{
	
	private Schema sch;
	private int recordLen;
	private int dbid;				//filename, one db one file
	private ArrayList<Integer> pageList;
	private HashMap<String, Integer> offsets;
	
	
	public TableInfo(int dbid, Schema sch){
		this.dbid = dbid;
		this.sch = sch;
		offsets = new HashMap<String, Integer>();
		int pos = 0;
		for(String fldName : sch.getFields()){
			offsets.put(fldName, pos);
			pos += fldLenInByte(fldName);
		}
		recordLen = pos;
		pageList = new ArrayList<Integer>();
	}
	
	public TableInfo(int dbid, Schema sch, HashMap<String, Integer> offsets, int recordLen){
		this.dbid = dbid;
		this.sch = sch;
		this.offsets = offsets;
		this.recordLen = recordLen;
	}
	
	public boolean isEmpty(){
		return pageList.isEmpty();
	}
	
	public boolean isKey(String fldName){
		return sch.getIsKey(fldName);
	}
	
	public int getDbid(){
		return dbid;
	}
	
	public int getTruePid(int num){
		return pageList.get(num);
	}
	
	public int getPageListId(int p){
		int count = 0;
		for(int pid : pageList){
			if(pid == p)
				return count;
			++count;
		}
		return -1;
	}
	
	public int getNextPid(int currentPid){
		int pos = pageList.indexOf(currentPid);
		if(pos == pageList.size()-1)
			return -1;
		return pageList.get(pos+1);
	}
	
	public int getPrePid(int currentPid){
		int pos = pageList.indexOf(currentPid);
		if(pos == 0)
			return -1;
		return pageList.get(pos-1);
	}
	
	public int getPageNum(){
		return pageList.size();
	}
	
	public void addPage(int prepid,int pid){
		if(prepid == -1){
			pageList.add(pid);
			return;
		}
		int pos = pageList.indexOf(prepid);
		pageList.add(pos+1, pid);
	}
	
	
	public int getRecordLen(){
		return recordLen;
	}
	
	public Schema getSchema(){
		return sch;
	}
	
	//offset doesn't insclude the first INT_SIZE flag
	public int getOffset(String fldName){
		return offsets.get(fldName);
	}
	
	private int fldLenInByte(String fldName){
		int type = sch.getType(fldName);
		if(type == INTEGER)
			return Transaction.getIntSize();
		else
			//IntSize denotes the string length
			return Transaction.getIntSize()+sch.getLen(fldName);
			//return getStringLenInByte(sch.getLen(fldName));
	}
	
	/**
	    * The maximum size, in bytes, of a string of length n.
	    * A string is represented as the encoding of its characters,
	    * preceded by an integer denoting the number of bytes in this encoding.
	    * If the JVM uses the US-ASCII encoding, then each char
	    * is stored in one byte, so a string of n characters
	    * has a size of 4+n bytes.
	    * @param n the size of the string
	    * @return the maximum number of bytes required to store a string of size n
	    */
	private int getStringLenInByte(int n){
		float bytesPerChar = Charset.defaultCharset().newEncoder().maxBytesPerChar();
		return (Transaction.getIntSize() + n*(int)bytesPerChar);
	}
	
}
